package org.JWCB.system.service.question.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import org.JWCB.common.core.constants.HttpConstants;
import org.JWCB.common.core.enums.QuestionTagEnums;
import org.JWCB.common.redis.service.RedisService;
import org.JWCB.system.domain.exam.entity.ExamQuestion;
import org.JWCB.system.domain.question.dto.QuestionAddDto;
import org.JWCB.system.domain.question.dto.QuestionEditDto;
import org.JWCB.system.domain.question.dto.QuestionQueryDto;
import org.JWCB.system.domain.question.entity.Question;
import org.JWCB.system.domain.question.es.QuestionES;
import org.JWCB.system.domain.question.vo.QuestionDetailVo;
import org.JWCB.system.domain.question.vo.QuestionListItemVo;
import org.JWCB.common.core.domain.vo.R;
import org.JWCB.common.core.enums.ResultCode;
import org.JWCB.common.core.exception.ServiceException;
import org.JWCB.system.domain.question.vo.QuestionTagVo;
import org.JWCB.system.elasticsearch.QuestionRepository;
import org.JWCB.system.manager.QuestionCacheManager;
import org.JWCB.system.mapper.exam.ExamQuestionMapper;
import org.JWCB.system.mapper.question.QuestionMapper;
import org.JWCB.system.mapper.question.QuestionTagMapper;
import org.JWCB.system.service.file.IFileService;
import org.JWCB.system.service.question.IQuestionService;
import org.JWCB.system.service.question.IQuestionTagService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


@Service
public class QuestionServiceImpl implements IQuestionService {
    private static final Logger log = LoggerFactory.getLogger(QuestionServiceImpl.class);
    @Autowired
    private QuestionMapper questionMapper;
    @Autowired
    private ExamQuestionMapper examQuestionMapper;


    @Autowired
    private RedisService redisService;
    @Autowired
    private QuestionRepository questionRepository;

    @Autowired
    private QuestionCacheManager questionCacheManager;


    private static final Pattern IMG_PATTERN = Pattern.compile("<img[^>]*src=\"([^\"]*)\"[^>]*>");
    @Autowired
    private IFileService fileService;

    @Autowired
    private QuestionTagMapper questionTagMapper;
    @Autowired
    private IQuestionTagService questionTagService;

    @Override
    public List<QuestionListItemVo> list(QuestionQueryDto questionQueryDto) {
        if(StrUtil.isNotEmpty(questionQueryDto.getExcludeIdsStr())) {
            Set<Long> excludeIds = Arrays.stream(questionQueryDto.getExcludeIdsStr().split(HttpConstants.SPLIT_SEM)).map(Long::valueOf).collect(Collectors.toSet());
            questionQueryDto.setExcludeIds(excludeIds);
        }
        PageHelper.startPage(questionQueryDto.getPageNum(),questionQueryDto.getPageSize());
        return questionMapper.selectQuestionList(questionQueryDto);
    }


    @Override
    @Transactional
    public int add(QuestionAddDto questionAddDto) {
        List<Question> questionList = questionMapper.selectList(new LambdaQueryWrapper<Question>().select(Question::getQuestionId).eq(Question::getTitle,questionAddDto.getTitle()));
        if(CollectionUtil.isNotEmpty(questionList)) {
            throw new ServiceException(ResultCode.FAILED_ALREADY_EXISTS);
        }
        questionAddDto.setContent(fileService.transferTempFiles(questionAddDto.getContent()));
        Question question = new Question();
        BeanUtil.copyProperties(questionAddDto,question);
        int res =  questionMapper.insert(question);
        if(res <= 0) {
            return 0;
        }
        questionTagService.setQuestionTag(question.getQuestionId(), questionAddDto.getQuestionTagCodes());
        // 插入es
        QuestionES questionES = BeanUtil.copyProperties(question, QuestionES.class);
        List<QuestionTagVo> questionTagVoList = getQuestionTagVosByCodes(questionAddDto);
        questionES.setQuestionTagList(questionTagVoList);
        questionRepository.save(questionES);
        // 插入redis
        questionCacheManager.addCache(question.getQuestionId());
        return res;
    }




    @Override
    public R<QuestionDetailVo> detail(Long questionId) {
        Question question = getQuestionById(questionId);
        QuestionDetailVo questionDetailVo = new QuestionDetailVo();
        BeanUtil.copyProperties(question,questionDetailVo);
        List<QuestionTagVo> questionTagVos = questionTagService.getQuestionAllTag(questionId);
        questionDetailVo.setQuestionTags(questionTagVos);
        return R.ok(questionDetailVo);
    }

    @Override
    @Transactional
    public int edit(QuestionEditDto questionEditDto) {
        Question oldQuestion = getQuestionById(questionEditDto.getQuestionId());
        checkCanEdit(questionEditDto.getQuestionId());
//        oldQuestion.setTitle(questionEditDto.getTitle());
//        oldQuestion.setDifficulty(questionEditDto.getDifficulty());
//        oldQuestion.setTimeLimit(questionEditDto.getTimeLimit());
//        oldQuestion.setSpaceLimit(questionEditDto.getSpaceLimit());
//        oldQuestion.setContent(questionEditDto.getContent());
//        oldQuestion.setQuestionCase(questionEditDto.getQuestionCase());
//        oldQuestion.setDefaultCode(questionEditDto.getDefaultCode());
//        oldQuestion.setMainFunc(questionEditDto.getMainFunc());
        BeanUtil.copyProperties(questionEditDto,oldQuestion);
        int res = questionMapper.updateById(oldQuestion);
        if(res <= 0) {
            return res;
        }
        questionTagService.setQuestionTag(questionEditDto.getQuestionId(), questionEditDto.getQuestionTagCodes());
        QuestionES questionES = BeanUtil.copyProperties(oldQuestion, QuestionES.class);
        List<QuestionTagVo> questionTagVoList = getQuestionTagVosByCodes(questionEditDto);
        questionES.setQuestionTagList(questionTagVoList);
        questionRepository.save(questionES);
        return res;
    }





    @Override
    public int del(Long questionId) {
        Question oldQuestion = getQuestionById(questionId);
        checkCanEdit(questionId);

        int res = questionMapper.deleteById(oldQuestion.getQuestionId());
        if(res <= 0) {
            return res;
        }
        questionRepository.deleteById(questionId);
        questionCacheManager.delCache(questionId);
        return res;
    }




    /**
     * 根据id获取question
     * @param questionId id
     * @return question
     */
    private Question getQuestionById(Long questionId) {
        Question oldQuestion = questionMapper.selectById(questionId);
        if(oldQuestion == null) {
            throw new ServiceException(ResultCode.FAILED_NOT_EXISTS);
        }
        return oldQuestion;
    }

    /**
     * 获取绑定当前题目的竞赛列表
     * @param questionId 题目id
     * @return 竞赛id列表
     */
    private List<Long> getExamByQuestionId(Long questionId) {
        List<ExamQuestion> examQuestionList = examQuestionMapper.selectList(
                new LambdaQueryWrapper<ExamQuestion>().eq(ExamQuestion::getQuestionId,questionId));
        return examQuestionList.stream().map(ExamQuestion::getExamId).collect(Collectors.toList());
    }


    /**
     * 判定能否对题目进行编辑
     * @param questionId 题目id
     */
    private void checkCanEdit(Long questionId) {
        List<Long> examIds = getExamByQuestionId(questionId);
        if(CollectionUtil.isNotEmpty(examIds)) {
            throw new ServiceException(ResultCode.QUESTION_HAS_BEAN_TIED_TO_THE_EXAM);
        }
    }


    /**
     * 通过codes获取vos
     * @param questionAddDto
     * @return
     */

    private  List<QuestionTagVo> getQuestionTagVosByCodes(QuestionAddDto questionAddDto) {
        List<QuestionTagVo> questionTagVoList = new ArrayList<>();
        for(Integer code : questionAddDto.getQuestionTagCodes()) {
            QuestionTagVo questionTagVo = new QuestionTagVo();
            QuestionTagEnums questionTagEnums = QuestionTagEnums.getByCode(code);
            questionTagVo.setCode(questionTagEnums.getCode());
            questionTagVo.setDesc(questionTagEnums.getDesc());
            questionTagVoList.add(questionTagVo);
        }
        return questionTagVoList;
    }


}
